package com.sdry.utils.zm;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.sdry.model.zc.ZcSysUserEntity;
import com.sdry.model.zm.LogModel;
import com.sdry.service.zm.LogModelService;

@Component
@Aspect
public class SystemLogAspect {


	private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);

	private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal<Date>("ThreadLocal beginTime");

	private static final ThreadLocal<LogModel> logThreadLocal = new NamedThreadLocal<LogModel>("ThreadLocal log");


	private LogModelService logModelService;


	/**
	 * Controller层切点 注解拦截
	 */
	@Pointcut("@annotation(com.sdry.utils.zm.MethodLog)")
	public void controllerAspect() {
	}



	/**
	 * 用于拦截Controller层记录用户的操作
	 *
	 * @param joinPoint   切点
	 */
	@Around("controllerAspect()")
	public Object doAfter(ProceedingJoinPoint joinPoint) throws Exception {
		LogModel logModel = new LogModel();
		System.out.println("Around 执行被切入对象前");
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		Date beginTime = new Date();
		beginTimeThreadLocal.set(beginTime);// 线程绑定变量（该数据只有当前请求的线程可见）
		if (logger.isDebugEnabled()) {// 这里日志级别为debug
			logger.debug("开始计时: {}  URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(beginTime), request.getRequestURI());
		}
		
		// 获取输入输出参数
		
		Object[] inParms = joinPoint.getArgs();
		Object outParms = null;
		// 执行被切入函数并获得返回值
		try {
			outParms = joinPoint.proceed();
		} catch (Throwable e1) {
			e1.printStackTrace();
		}
		logModel.setInPrams(inParms);
		logModel.setOutPram(outParms);
		
		System.out.println("Around 执行被切入对象后");
		// 读取session中的用户
		HttpSession session = request.getSession();

		String title = "";
		String type = "info"; // 日志类型(info:入库,error:错误)
		String remoteAddr = request.getRemoteAddr();// 请求的IP
		String requestUri = request.getRequestURI();// 请求的Uri
		try {
			title = getControllerMethodDescription(joinPoint);
		} catch (Exception e) {
			e.printStackTrace();
		}
		logModel.setTitle(title);
		logModel.setType(type);
		logModel.setRemoteAddr(remoteAddr);
		logModel.setRequestUri(requestUri);
		logModel.setException("无异常");

		ZcSysUserEntity users = (ZcSysUserEntity) session.getAttribute("user");

		logModel.setUserId(users.getId());
		System.out.println(users);
		logModel.setUserName(users.getUserName());

		Date date = new Date();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String format = simpleDateFormat.format(date);
		logModel.setAddTime(format);
	
		//logModelService.save(logModel);
		logThreadLocal.set(logModel);
		
		System.out.println("Around 执行结束");
		return outParms;
	}

	/**
	 * 异常通知 记录操作报错日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
		LogModel logModel = logThreadLocal.get();
		logModel.setType("error");
		logModel.setException(e.toString());
		//logModelService.save(logModel);;
	}

	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * 
	 * @param joinPoint  切点
	 * @return 方法描述
	 */

	public static String getControllerMethodDescription(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		MethodLog controllerLog = method.getAnnotation(MethodLog.class);
		String discription = controllerLog.remarks();
		return discription;
	}

	/**
	 * 将输入参数数组转化成String
	 * 
	 * @param inPrams 输入参数数组
	 * @return
	 */
	public static String toStringInPram(Object[] inPrams){
		String rtn = null;
		StringBuilder strbd = new StringBuilder();
		for (Object object : inPrams) {
			strbd.append(object.toString());
		}
		rtn = strbd.toString();
		return rtn;
	}
}
